package com.gitee.apanlh.util.base;

import com.gitee.apanlh.exp.InitLoadException;
import com.gitee.apanlh.util.func.FuncFilter;
import com.gitee.apanlh.util.func.FuncMapExecute;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.reflection.ClassUtils;
import com.gitee.apanlh.util.reflection.ReflectionUtils;
import com.gitee.apanlh.util.valid.ValidParam;

import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

/**	
 * 	Map工具类
 * 	
 * 	@author Pan
 */
public class MapUtils {
	
	/**
	 * 	构造函数
	 * 
	 * 	@author Pan
	 */
	private MapUtils() {
		//	不允许外部实例
		super();
	}
	
	/**	
	 * 	比较两者Map
	 * 	<br>value匹配模式(比较Map中的value值)
	 * 	<br>不严格限制顺序
	 * 
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	compareMap1		Map1
	 * 	@param 	compareMap2		Map2
	 * 	@return	boolean
	 */
	public static <K, V> boolean eqByValue(Map<K, V> compareMap1, Map<K, V> compareMap2) {
		return eq(compareMap1, compareMap2, false);
	}
	
	/**	
	 * 	比较两者Map
	 * 	<br>key+value匹配模式(比较Map中的key+value值)
	 * 	<br>不严格限制顺序
	 * 
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	compareMap1		Map1
	 * 	@param 	compareMap2		Map2
	 * 	@return	boolean
	 */
	public static <K, V> boolean eqByKeyValue(Map<K, V> compareMap1, Map<K, V> compareMap2) {
		return eq(compareMap1, compareMap2, true);
	}
	
	/**	
	 * 	比较两者Map
	 * 	<br>其中比较规则Key+Value值
	 * 	<br>严格要求按照顺序比较
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	compareMap1		Map1
	 * 	@param 	compareMap2		Map2
	 * 	@return	boolean
	 */
	public static <K, V> boolean eqByOrder(Map<K, V> compareMap1, Map<K, V> compareMap2) {
		if (isEmpty(compareMap1) || isEmpty(compareMap2) 
				|| compareMap1.size() != compareMap2.size()) {
			return false;
		}

		if (compareMap1 == compareMap2) {
			return true;
		}
		//	验证类型
		if (!ClassUtils.eq(compareMap1.keySet().iterator().next().getClass(), compareMap2.keySet().iterator().next().getClass())) {
			return false;
		}
			
		//	比较Key值以及Value
		Iterator<Entry<K, V>> iterator = IteratorUtils.entrySet(compareMap1);
		Iterator<Entry<K, V>> iterator2 = IteratorUtils.entrySet(compareMap2);
		while (iterator.hasNext()) {
			Entry<K, V> next = iterator.next();
			Entry<K, V> next2 = iterator2.next();
			if (!ObjectUtils.eq(next.getKey(), next2.getKey()) && !ObjectUtils.eq(next.getValue(), next2.getValue())) {
				return false;
			}
		}
		return true;
	}
	
	/**	
	 * 	比较Map
	 * 	<br>不严格限制顺序
	 * 	<br>true则比较key + value模式
	 * 	<br>false则比较value模式
	 * 	
	 * 	@author Pan
	 * 	@param 	compareMap1		Map1
	 * 	@param 	compareMap2		Map2
	 * 	@param 	equalsMode		false则只比较value	true比较key以及value
	 * 	@return	boolean
	 */
	private static <K, V> boolean eq(Map<K, V> compareMap1, Map<K, V> compareMap2, boolean equalsMode) {
		if (isEmpty(compareMap1) || isEmpty(compareMap2) 
				|| compareMap1.size() != compareMap2.size()) {
			return false;
		}

		if (compareMap1 == compareMap2) {
			return true;
		}
		//	是否验证包含key+value模式
		if (!equalsMode) {
			return CollUtils.eq(compareMap1.values(), compareMap2.values());
		}
		//	验证类型
		if (!ClassUtils.eq(compareMap1.keySet().iterator().next().getClass(), compareMap2.keySet().iterator().next().getClass())) {
			return false;
		}
		
		//	比较Key值以及Value
		Iterator<Entry<K, V>> iterator = IteratorUtils.entrySet(compareMap1);
		//	验证值
		while (iterator.hasNext()) {
			Entry<K, V> next = iterator.next();
			V compareMapValue2 = compareMap2.get(next.getKey());
			if (compareMapValue2 == null || !ObjectUtils.eq(compareMapValue2, next.getValue())) {
				return false;
			}
		}
		return true;
	}
	
	/**	
	 * 	过滤Value值
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map			原始Map
	 * 	@param 	filterValue	过滤条件
	 */
	public static <K, V> void filter(Map<K, V> map, Object filterValue) {
		if (isEmpty(map) || filterValue == null) {
			return ;
		}
		
		IteratorUtils.values(map, (value, iterator) -> {
			if (ObjectUtils.eq(value, filterValue)) {
				iterator.remove();
			}
		});
	}
	
	/**		
	 * 	过滤(在Map中如果包含另一个Map值则移除原始Map)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map			原始Map
	 * 	@param 	filterMap	过滤条件
	 */
	public static <K, V> void filter(Map<K, V> map, Map<K, V> filterMap) {
		if (isEmpty(map) || isEmpty(filterMap)) {
			return ;
		}
		
		IteratorUtils.entrySet(filterMap, (key, value, iterator) -> map.remove(key, value));
	}
	
	/**	
	 * 	过滤(数据来源与集合)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map			原始Map
	 * 	@param 	filterList	过滤条件
	 */
	public static <K, V> void filter(Map<K, V> map, List<V> filterList) {
		if (ValidParam.isEmpty(map) || ValidParam.isEmpty(filterList)) {
			return ;
		}
		map.values().removeAll(filterList);
	}
	
	/**	
	 * 	过滤(自定义条件)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map			原始Map
	 * 	@param 	filter		过滤条件
	 */
	public static <K, V> void filter(Map<K, V> map, FuncFilter<V> filter) {
		if (isEmpty(map)) {
			return ;
		}
		
		IteratorUtils.values(map, (value, iterator) -> {
			if (filter.accept(value)) {
				iterator.remove();
			}
		});
	}
	
	/**	
	 * 	根据value查找相对应的key
	 * 	
	 * 	@author Pan
	 *  @param  <K>     	键类型
	 *  @param  <V>     	值类型
	 * 	@param searchMap	map
	 * 	@param value   		值
	 * 	@return	Map 	返回一个或多个key值
	 */
	public static <K, V> Map<K, V> getKeysByValue(Map<K, V> searchMap, V value) {
		if (value == null) {
			return Empty.map();
		}
		
		return newHashMap(newMap -> 
			IteratorUtils.entrySet(searchMap, (nextKey, nextValue, iterator) -> {
				if (ObjectUtils.eq(value, nextValue)) {
					newMap.put(nextKey, nextValue);
				}
			})
		);
	}
	
	/**	
	 * 	验证map是否为空
	 * 
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param  map		map
	 * 	@return	boolean
	 */
	public static <K, V> boolean isEmpty(Map<K, V> map) {
		return null == map || map.size() == 0;
	}
	
	/**	
	 * 	构建HashMap(K, V, 16)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newHashMap() {
		return newHashMap(16);
	}
	
	/**	
	 * 	构建HashMap(K, V, 自定义容量)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	initialCapacity	初始化容量
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newHashMap(int initialCapacity) {
		return new HashMap<>(initialCapacity);
	}
	
	/**
	 * 	构建HashMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map		Map
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newHashMap(Map<K, V> map) {
		return new HashMap<>(map);
	}
	
	/**	
	 * 	构建HashMap(K, V, 自定义初始化方法)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	funcMapExecute	初始化执行函数
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newHashMap(FuncMapExecute<K, V> funcMapExecute) {
		return newHashMap(funcMapExecute, 16);
	}
	
	/**
	 *	构建HashMap(K, V, 自定义初始化方法,	初始化容量)
	 *	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	funcMapExecute		初始化执行函数
	 * 	@param 	initialCapacity		初始化容量
	 *	@return	Map
	 */
	public static <K, V> Map<K, V> newHashMap(FuncMapExecute<K, V> funcMapExecute, int initialCapacity) {
		Map<K, V> map = newHashMap(initialCapacity);
		try {
			funcMapExecute.execute(map);
		} catch (Exception e) {
			throw new InitLoadException(e.getMessage(), e);
		}
		return map;
	}
	
	/**
	 * 	构建LinkedHashMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newLinkedHashMap() {
		return newLinkedHashMap(16);
	}
	
	/**
	 * 	构建LinkedHashMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	initialCapacity		初始化容量
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newLinkedHashMap(int initialCapacity) {
		return new LinkedHashMap<K, V>(initialCapacity);
	}
	
	/**	
	 * 	构建LinkedHashMap(K, V, 自定义初始化方法)
	 * 	<br>默认容量16
	 * 
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	funcMapExecute	初始化执行函数
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newLinkedHashMap(FuncMapExecute<K, V> funcMapExecute) {
		return newLinkedHashMap(funcMapExecute, 16);
	}
	
	/**
	 *	构建LinkedHashMap(K, V, 自定义初始化方法,	初始化容量)
	 *	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	funcMapExecute		初始化执行函数
	 * 	@param 	initialCapacity		初始化容量
	 *	@return	Map
	 */
	public static <K, V> Map<K, V> newLinkedHashMap(FuncMapExecute<K, V> funcMapExecute, int initialCapacity) {
		Map<K, V> newLinkedHashMap = newLinkedHashMap(initialCapacity);
		try {
			funcMapExecute.execute(newLinkedHashMap);
			return newLinkedHashMap;
		} catch (Exception e) {
			throw new InitLoadException(e.getMessage(), e);
		}
	}
	
	/**
	 * 	构建LinkedHashMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map		Map
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newLinkedHashMap(Map<K, V> map) {
		return new LinkedHashMap<>(map);
	}
	
	/**	
	 *	构造ConcurrentHashMap
	 *	 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newConcurrentHashMap() {
		return newConcurrentHashMap(16);
	}
	
	/**	
	 *	构建ConcurrentHashMap
	 *	 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 *  @param  initialCapacity 容量
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newConcurrentHashMap(int initialCapacity) {
		return new ConcurrentHashMap<>(initialCapacity);
	}
	
	/**	
	 *	构造ConcurrentHashMap
	 *	 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map    	map
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newConcurrentHashMap(Map<K, V> map) {
		return new ConcurrentHashMap<>(map);
	}
	
	/**	
	 *	构造ConcurrentHashMap
	 *	<br>自定义初始函数
	 *	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param	funcMapExecute 初始化执行函数
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newConcurrentHashMap(FuncMapExecute<K, V> funcMapExecute) {
		return newConcurrentHashMap(funcMapExecute, 16);
	}
	
	/**	
	 *	构造ConcurrentHashMap
	 *	<br>自定义初始函数
	 *	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param	funcMapExecute 	初始化执行函数
	 * 	@param	initialCapacity 初始化容量
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newConcurrentHashMap(FuncMapExecute<K, V> funcMapExecute, int initialCapacity) {
		Map<K, V> newConcurrentHashMap = newConcurrentHashMap(initialCapacity);
		try {
			funcMapExecute.execute(newConcurrentHashMap);
		} catch (Exception e) {
			throw new InitLoadException(e.getMessage(), e);
		}
		return newConcurrentHashMap;
	}
	
	/**	
	 * 	构造EnumMap({@code Enum<K>, Object})
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	keyType		键类型
	 * 	@return	Map
	 */
	public static <K extends Enum<K>, V> Map<K, V> newEnumMap(Class<K> keyType) {
		return new EnumMap<>(keyType);
	}
	
	/**	
	 * 	构建newWeakHashMap(K, V, 16)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newWeakHashMap() {
		return newWeakHashMap(16);
	}
	
	/**	
	 * 	构建newWeakHashMap(K, V, 自定义容量)
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	initialCapacity	初始化容量
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newWeakHashMap(int initialCapacity) {
		return new WeakHashMap<>(initialCapacity);
	}
	
	/**	
	 * 	构造EnumMap({@code Enum<K>, String})
	 * 	<br> 添加枚举类中的value
	 * 	<br> 如果需要改变枚举的value值则枚举类需要重写toString()方法
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 * 	@param 	keyType		键类型
	 * 	@param 	values		枚举values数组
	 * 	@return	Map
	 */
	public static <K extends Enum<K>> Map<K, String> newEnumMap(Class<K> keyType, K[] values) {
		Map<K, String> enumMap = newEnumMap(keyType);
		for (K k : values) {
			enumMap.put(k, k.toString());
		}
		return enumMap;
	}
	
	/**	
	 * 	构造EnumMap({@code Enum<K>, String})
	 * 	<br> 将某个字段属性值作为枚举类中的value
	 * 	
	 * 	@author Pan
	 *  @param  <K>     	键类型
	 * 	@param 	keyType		键类型
	 * 	@param 	values		枚举values数组
	 * 	@param 	fieldName	字段名
	 * 	@return	Map
	 */
	public static <K extends Enum<K>> Map<K, String> newEnumMap(Class<K> keyType, K[] values, String fieldName) {
		Map<K, String> enumMap = newEnumMap(keyType);
		for (K k : values) {
			Object fieldValue = ReflectionUtils.getFieldValue(k, fieldName);
			enumMap.put(k, fieldValue == null ? null : fieldValue.toString());
		}
		return enumMap;
	}

	/**	
	 * 	构建TreeMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newTreeMap() {
		return new TreeMap<>();
	}
	
	/**	
	 * 	构建TreeMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param	map		map
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newTreeMap(Map<K, V> map) {
		return new TreeMap<>(map);
	}
	
	/**	
	 * 	构建TreeMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param	sortedMap	map
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newTreeMap(SortedMap<K, V> sortedMap) {
		return new TreeMap<>(sortedMap);
	}
	
	/**	
	 * 	构建TreeMap
	 * 	
	 * 	@author Pan
	 *  @param  <K>     	键类型
	 *  @param  <V>     	值类型
	 * 	@param	comparator	对比器
	 * 	@return	Map
	 */
	public static <K, V> Map<K, V> newTreeMap(Comparator<K> comparator) {
		return new TreeMap<>(comparator);
	}
	
	/**	
	 * 	字符串转换Map
	 * 	<br>Key值为索引
	 * 	<br>value值为字符串值
	 * 	
	 * 	@author Pan
	 * 	@param  arr		字符数组
	 * 	@return	Map
	 */
	public static Map<String, String> toHashMap(String... arr) {
		if (ArrayUtils.isEmpty(arr)) {
			return Empty.map();
		}
		
		return newHashMap(newMap -> {
			for (int i = 0, len = arr.length; i < len; i++) {
				newMap.put(ClassConvertUtils.toStr(i), arr[i]);
			}
		}, arr.length);
	}
	
	/**		
	 * 	Map转换ArrayList
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map		map
	 * 	@return	Map
	 */
	public static <K, V> List<V> toArrayList(Map<K, V> map) {
		return CollUtils.newArrayList(map);
	}
	
	/**
	 * 	Map转换LinkedList	
	 * 	
	 * 	@author Pan
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	map		map
	 * 	@return	Map
	 */
	public static <K, V> List<V> toLinkedList(Map<K, V> map) {
		return CollUtils.newLinkedList(map);
	}
}
